# *-*- coding:utf-8 -*-
# @Author  : Eliza
# @Time    : 2021/7/18 15:09
# @Software : RubyMine
# ruby yield yield关键字我是这样理解，用它来占一个位置，先标记下这个地方将来要写代码的，等到调用的时候，再来编写具体的代码。

# 块参数也可以明确给定，形式就是在参数前面加一个"&"，比如 def fn(arg1, arg2, &block) end，其中的 &block 就是明确给定的块参数。
# 块参数的动作，可以通过调用 call() 方法执行，还可以用 yield 来执行 —— yield 其实就是一个语法糖。
#method receives an invisible block argument
def foo1()
  yield 1
end

#specify it explicitly
def foo2(&block)
  #method 定义中 &block 参数必须在最后
  yield 1
end

#yield is equal to block.call
def foo3(&block)
  block.call(1)
end

#function call
foo1 { |x| puts x } # => 1
foo2 { |x| puts x } # => 1
foo3 { |x| puts x } # => 1

=begin
所有方法都可以隐式或显式指定一个块参数，那么块参数到底是什么呢？
答案是 Proc 对象，一个具有 call 方法的对象。
  Proc 对象的定义有几种形式：
  直接使用 {}
  使用 Proc.new {}
  使用 proc {}
  使用 lambda {}
=end

puts "---yield is equal to block.call"

def foo(&block)
  puts block.class
  puts block.to_s
  yield 1
end

#function call
# Proc created using {} syntax
foo { |x| puts x }
# => Proc
# => #<Proc:0x00000000e0b140@(ruby):9>
# => 1
#创建 Proc
puts "--- Proc created with the 'proc' keyword. Note & syntax when calling."
my_proc = proc { |n| puts n }
foo(&my_proc)
puts "------Proc . new"
my_proc = Proc.new { |n| puts n }
foo(&my_proc)
# Proc created with the "lambda" keyword. Nearly same thing.
my_proc = lambda { |n| puts n }
foo(&my_proc)

# yield self
# 在一个对象中，self 表示是一个当前对象的引用。
# 所以，常见的 yield self if block_given? 中的 self 就和其它地方使用 self 一样，没什么特殊的。
class C1
  def foo1(&block)
    puts block.class
    puts block.to_s
    yield self if block_given?
    yield "AAAAAAAAA"
  end
end

class C2
  def foo2(&block)
    puts block.class
    puts block.to_s
    yield self if block_given?
    yield "BBBBBBBBB"
  end

  def to_s
    "XXXXXXXXXX"
  end
end

puts "--------C1---"
c1 = C1.new
c1.foo1 { |x| puts x.to_s + "::" } #给了 block 则执行
puts "--------C2---"

c2 = C2.new
c2.foo2 { |x| puts x }
puts "--------foo( 1, 2, &block)---"

def foo11(arg1, arg2, &block)
  puts block

end

#function call
block = proc { |x| puts x }
foo11(1, 2, &block)
puts "----yield 相当于是 block.call() 方法的调用，所以参数个数也需要对应"

def foo12()
  yield 1, 2, 3 # 这里的 1 2 3 就是传递的参数
end

#function call
foo12 { |x| puts x } # => 1
foo12 { |x, y, z| puts z } # => 3
foo12 { |x, y, z, k| puts k } # 为空